﻿using System;
using System.Data;
using System.Windows.Forms.DataVisualization.Charting;

namespace LeakView.common
{

    public class ChartDataSource
    {
        private DataTable source;

        private const string xkey = "X";
        private const string ykey = "Y";

        public TimeSpan MaxTimeSpan { get; set; } = TimeSpan.MaxValue;

        public int MaxPointCount { get; set; } = int.MaxValue;

        public ChartDataSource()
        {
            source = new DataTable();
            source.Columns.Add(xkey, typeof(DateTime));
            source.Columns.Add(ykey, typeof(double));
        }

        public double LastY
        {
            get
            {
                int count = source.Rows.Count;
                if (count == 0)
                {
                    return double.NaN;
                }
                else
                {
                    return (double)source.Rows[count - 1][ykey];
                }
            }
        }

        public double MaxY
        {
            get
            {
                double result = double.NaN;

                for(int i = 0; i < source.Rows.Count; i++)
                {
                    var v = (double)source.Rows[i][ykey];

                    if(double.IsNaN(result) || v > result)
                    {
                        result = v;
                    }

                }

                return result;
            }
        }

        public double MinY
        {
            get
            {
                double result = double.NaN;

                for (int i = 0; i < source.Rows.Count; i++)
                {
                    var v = (double)source.Rows[i][ykey];

                    if (double.IsNaN(result) || v < result)
                    {
                        result = v;
                    }

                }

                return result;
            }
        }


        public void Bind(Chart chart)
        {
            Bind(chart, 0);
        }

        public void Bind(Chart chart, int seriesIndex)
        {
            if (chart.InvokeRequired)
            {
                chart.Invoke(new Action(() => {
                    Bind(chart, seriesIndex);
                }));
            }
            else
            {
                chart.Series[seriesIndex].Points.DataBind(source.AsEnumerable(), xkey, ykey, "");
                /*
                chart.DataSource = source;
                chart.Series[seriesIndex].XValueMember = xkey;
                chart.Series[seriesIndex].YValueMembers = ykey;
                chart.DataBind();
                */
            }
        }

        public ChartDataSource Clear()
        {
            source.Rows.Clear();
            return this;
        }

        public ChartDataSource Add(DateTime x, double y)
        {
            source.Rows.Add(x, y);
            this.filterSpan(MaxTimeSpan);
            this.filterCount(MaxPointCount);
            return this;
        }

        public ChartDataSource filterSpan()
        {
            return filterSpan(this.MaxTimeSpan);
        }

        public ChartDataSource filterSpan(TimeSpan span)
        {
            if(source.Rows.Count > 2)
            {
                DateTime last = (DateTime)source.Rows[source.Rows.Count - 1][xkey];

                while(source.Rows.Count > 1)
                {
                    DateTime first = (DateTime)source.Rows[0][xkey];
                    TimeSpan ts = last - first;
                    if (ts.Duration() > span)
                    {
                        source.Rows.RemoveAt(0);
                    }
                    else
                    {
                        break;
                    }

                }
            }
            return this;
        }

        public ChartDataSource filterCount(int count)
        {
            if (count > 0)
            {
                while (source.Rows.Count > count)
                {
                    source.Rows.RemoveAt(0);
                }
            }
            return this;
        }

    }
}
